import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 预定数据模型类
 * 
 * 这个类用来表示酒店的一条房间预定记录
 * 预定是客人在实际入住之前就确定要住某个房间的过程
 * 
 * 在酒店管理系统中的业务流程：
 * 1. 客人打电话或在线预定房间 -> 创建Reservation对象
 * 2. 客人到达酒店办理入住 -> 将Reservation转换为CheckIn
 * 3. 客人退房结账 -> CheckIn移动到History历史记录
 * 
 * 预定记录包含的信息：
 * - 预定编号：唯一标识这次预定
 * - 客人信息：谁预定的
 * - 房间信息：预定哪个房间
 * - 时间信息：什么时候入住和退房
 * - 费用信息：预计花费多少钱
 * - 状态信息：预定的当前状态
 * 
 * 与其他类的关系：
 * - Guest类：存储预定客人的基本信息
 * - Room类：存储被预定房间的信息
 * - CheckIn类：当客人实际入住时，预定转换为入住记录
 */
public class Reservation {
    // ==================== 成员变量定义 ====================
    // 这些变量存储了一次预定的所有重要信息

    private String reservationId; // 预定编号，每个预定的唯一标识（如：R2025052001）
    private String guestId; // 客人ID，关联到Guest表，标识是哪位客人预定的
    private String guestName; // 客人姓名，冗余存储，方便显示和查询
    private String roomNumber; // 房间号，标识预定的是哪个房间
    private String checkInDate; // 预计入住日期，格式：yyyy-MM-dd
    private String checkOutDate; // 预计退房日期，格式：yyyy-MM-dd
    private double totalAmount; // 预计总费用，根据房间价格和预定天数计算
    private String status; // 预定状态：已预定、已入住、已取消

    /**
     * 构造方法 - 创建一个新的预定记录
     * 
     * 当客人预定房间时，系统会调用这个构造方法创建Reservation对象
     * 所有参数都是必需的，确保预定信息的完整性
     * 
     * 使用示例：
     * Reservation reservation = new Reservation(
     * "R2025052001", // 预定编号
     * "G1716134400001", // 客人ID
     * "张三", // 客人姓名
     * "105", // 房间号
     * "2025-05-25", // 入住日期
     * "2025-05-28", // 退房日期
     * 600.0, // 总金额
     * "已预定" // 状态
     * );
     * 
     * @param reservationId 预定编号 - 系统生成的唯一标识
     * @param guestId       客人ID - 必须是已存在的客人
     * @param guestName     客人姓名 - 用于显示和搜索
     * @param roomNumber    房间号 - 必须是有效且可预定的房间
     * @param checkInDate   入住日期 - 不能是过去的日期
     * @param checkOutDate  退房日期 - 必须晚于入住日期
     * @param totalAmount   总金额 - 房间价格×天数
     * @param status        预定状态 - 通常初始为"已预定"
     */
    public Reservation(String reservationId, String guestId, String guestName, String roomNumber,
            String checkInDate, String checkOutDate, double totalAmount, String status) {
        // 使用this关键字将参数值赋给成员变量
        // this.成员变量 = 参数; 这是Java构造方法的标准写法
        this.reservationId = reservationId;
        this.guestId = guestId;
        this.guestName = guestName;
        this.roomNumber = roomNumber;
        this.checkInDate = checkInDate;
        this.checkOutDate = checkOutDate;
        this.totalAmount = totalAmount;
        this.status = status;
    }

    // ==================== Getter方法区域 ====================
    // 这些方法用于获取预定记录的各项信息
    // 在预定管理界面中，这些信息会显示给用户查看

    /**
     * 获取预定编号
     * 
     * 预定编号是每个预定的唯一标识，通常格式为：R + 年月日 + 序号
     * 例如：R2025052001 表示2025年5月20日的第1个预定
     * 
     * 用途：
     * 1. 客人查询预定时提供预定号
     * 2. 系统内部查找和管理预定记录
     * 3. 客服处理预定相关问题时的凭证
     * 
     * @return 预定的唯一编号
     */
    public String getReservationId() {
        return reservationId;
    }

    /**
     * 获取客人ID
     * 
     * 客人ID是连接预定记录和客人详细信息的桥梁
     * 通过这个ID可以查询到客人的联系方式、身份信息等
     * 
     * @return 预定客人的唯一标识ID
     */
    public String getGuestId() {
        return guestId;
    }

    /**
     * 获取客人姓名
     * 
     * 客人姓名存储在这里是为了方便显示和搜索
     * 这样在显示预定列表时不需要每次都去查询Guest表
     * 这种做法叫做"数据冗余"，用存储空间换取查询速度
     * 
     * @return 预定客人的姓名
     */
    public String getGuestName() {
        return guestName;
    }

    /**
     * 获取房间号
     * 
     * 房间号标识客人预定的是哪个房间
     * 在预定管理中，经常需要按房间号查询预定情况
     * 
     * @return 被预定的房间号
     */
    public String getRoomNumber() {
        return roomNumber;
    }

    /**
     * 获取预计入住日期
     * 
     * 这是客人计划到达酒店并入住的日期
     * 酒店会根据这个日期安排房间和服务
     * 
     * @return 预计入住日期，格式：yyyy-MM-dd
     */
    public String getCheckInDate() {
        return checkInDate;
    }

    /**
     * 获取预计退房日期
     * 
     * 这是客人计划离开酒店的日期
     * 用于计算住宿天数和总费用
     * 
     * @return 预计退房日期，格式：yyyy-MM-dd
     */
    public String getCheckOutDate() {
        return checkOutDate;
    }

    /**
     * 获取预计总金额
     * 
     * 总金额 = 房间单价 × 预定天数
     * 这个金额在客人入住时收取，或者在预定时收取定金
     * 
     * @return 预计总费用（单位：元）
     */
    public double getTotalAmount() {
        return totalAmount;
    }

    /**
     * 获取预定状态
     * 
     * 预定状态说明：
     * - "已预定"：预定成功，等待客人入住
     * - "已入住"：客人已经到达并办理了入住手续
     * - "已取消"：预定被取消（客人主动取消或超时未到）
     * - "已完成"：客人已经退房结账，预定流程结束
     * 
     * @return 当前预定状态
     */
    public String getStatus() {
        return status;
    }

    // ==================== Setter方法区域 ====================
    // 这些方法用于修改预定记录的信息
    // 在预定管理过程中，某些信息可能需要更新

    /**
     * 设置预定编号
     * 
     * 注意：预定编号通常在创建时确定，不应该随意修改
     * 这里提供setter主要是为了数据模型的完整性
     * 
     * @param reservationId 新的预定编号
     */
    public void setReservationId(String reservationId) {
        this.reservationId = reservationId;
    }

    /**
     * 设置客人ID
     * 
     * 在特殊情况下可能需要修改预定的客人
     * 比如客人信息录入错误，或者转让预定等
     * 
     * @param guestId 新的客人ID
     */
    public void setGuestId(String guestId) {
        this.guestId = guestId;
    }

    /**
     * 设置客人姓名
     * 
     * 当客人ID改变时，姓名也需要同步更新
     * 或者客人的姓名信息发生变化时需要更新
     * 
     * @param guestName 新的客人姓名
     */
    public void setGuestName(String guestName) {
        this.guestName = guestName;
    }

    /**
     * 设置房间号
     * 
     * 在以下情况下可能需要更换房间：
     * 1. 原预定房间出现故障
     * 2. 客人要求升级或降级房间
     * 3. 酒店需要调整房间安排
     * 
     * @param roomNumber 新的房间号
     */
    public void setRoomNumber(String roomNumber) {
        this.roomNumber = roomNumber;
    }

    /**
     * 设置预计入住日期
     * 
     * 客人可能会要求修改入住日期
     * 修改入住日期时，可能需要重新计算总金额
     * 
     * @param checkInDate 新的入住日期
     */
    public void setCheckInDate(String checkInDate) {
        this.checkInDate = checkInDate;
    }

    /**
     * 设置预计退房日期
     * 
     * 客人可能会要求延长或缩短住宿时间
     * 修改退房日期时，需要重新计算总金额
     * 
     * @param checkOutDate 新的退房日期
     */
    public void setCheckOutDate(String checkOutDate) {
        this.checkOutDate = checkOutDate;
    }

    /**
     * 设置预计总金额
     * 
     * 当入住天数改变或房间价格调整时，需要更新总金额
     * 也可能因为折扣、优惠等原因需要调整金额
     * 
     * @param totalAmount 新的总金额
     */
    public void setTotalAmount(double totalAmount) {
        this.totalAmount = totalAmount;
    }

    /**
     * 设置预定状态
     * 
     * 这是一个重要的方法，用于更新预定的状态
     * 状态变化的典型流程：
     * 已预定 -> 已入住 -> (CheckIn记录) -> 已完成
     * 或者：已预定 -> 已取消
     * 
     * @param status 新的预定状态
     */
    public void setStatus(String status) {
        this.status = status;
    }

    // ==================== 数据持久化方法 ====================
    // 这些方法用于将预定记录保存到文件或从文件中读取

    /**
     * 将预定记录转换为文件存储格式
     * 
     * 这个方法将预定的所有信息按照特定格式组合成字符串
     * 用于保存到reservations.txt文件中
     * 
     * 文件格式：预定号|客人ID|客人姓名|房间号|入住日期|退房日期|总金额|状态
     * 示例：R2025052001|G1716134400001|张三|105|2025-05-25|2025-05-28|600.0|已预定
     * 
     * 字段说明：
     * - 预定号：唯一标识这个预定
     * - 客人ID：关联客人详细信息
     * - 客人姓名：方便显示和搜索
     * - 房间号：标识预定的房间
     * - 入住日期：预计入住时间
     * - 退房日期：预计退房时间
     * - 总金额：预计费用
     * - 状态：当前预定状态
     * 
     * 为什么使用"|"作为分隔符？
     * 1. "|"字符在姓名、地址等文本中很少出现
     * 2. 比逗号更安全（姓名中可能有逗号）
     * 3. 比空格更明确（姓名中可能有空格）
     * 4. 便于程序解析和人工查看
     * 
     * @return 格式化的字符串，可直接写入文件
     */
    public String toFileString() {
        // 使用字符串连接操作符"+"将所有字段连接起来
        // 注意字段的顺序要与fromFileString()方法中的解析顺序保持一致
        return reservationId + "|" + guestId + "|" + guestName + "|" + roomNumber + "|" +
                checkInDate + "|" + checkOutDate + "|" + totalAmount + "|" + status;
    }

    /**
     * 从文件格式的字符串创建Reservation对象
     * 
     * 这是一个静态工厂方法（Static Factory Method）
     * 静态方法的特点：
     * 1. 属于类而不是对象，可以直接通过类名调用
     * 2. 不能访问非静态的成员变量和方法
     * 3. 常用于创建对象的工厂方法
     * 
     * 这个方法的作用：
     * 1. 系统启动时读取reservations.txt文件
     * 2. 将文件中的每一行数据转换为Reservation对象
     * 3. 加载到内存中供程序使用
     * 
     * 解析过程：
     * 1. 使用split()方法按"|"分割字符串
     * 2. 验证分割后的字段数量是否正确
     * 3. 将各个字段转换为相应的数据类型
     * 4. 创建并返回Reservation对象
     * 
     * 错误处理：
     * - 字段数量不正确：返回null
     * - 数字格式错误：抛出NumberFormatException异常
     * 
     * @param line 从文件中读取的一行数据
     * @return 创建的Reservation对象，如果数据格式错误则返回null
     */
    public static Reservation fromFileString(String line) {
        // 使用split()方法分割字符串
        // "\\|"是正则表达式，表示以"|"字符分割
        //
        // 为什么要写成"\\|"而不是"|"？
        // 1. split()方法的参数是正则表达式
        // 2. 在正则表达式中，"|"是特殊字符，表示"或"的意思
        // 3. 要表示字面意思的"|"字符，需要用反斜杠转义：\|
        // 4. 在Java字符串中，反斜杠本身也需要转义，所以写成\\|
        String[] parts = line.split("\\|");

        // 数据验证：检查分割后的数组长度
        // Reservation对象有8个字段，所以数组长度应该是8
        if (parts.length == 8) {
            // 解析各个字段并创建Reservation对象
            // 数组索引对应的字段：
            // parts[0] = 预定号（String）
            // parts[1] = 客人ID（String）
            // parts[2] = 客人姓名（String）
            // parts[3] = 房间号（String）
            // parts[4] = 入住日期（String）
            // parts[5] = 退房日期（String）
            // parts[6] = 总金额（需要转换为double）
            // parts[7] = 状态（String）

            // Double.parseDouble()方法将字符串转换为double类型
            // 如果字符串不是有效的数字格式，会抛出NumberFormatException异常
            return new Reservation(parts[0], parts[1], parts[2], parts[3],
                    parts[4], parts[5], Double.parseDouble(parts[6]), parts[7]);
        }

        // 如果数据格式不正确，返回null
        // 调用这个方法的代码需要检查返回值是否为null
        return null;
    }

    /**
     * 重写toString()方法，提供友好的字符串表示
     * 
     * toString()是Object类的方法，所有Java类都继承自Object类
     * 
     * @Override注解表示我们要重写（覆盖）父类的方法
     * 
     *                             重写toString()的好处：
     *                             1. 调试时可以方便地查看对象内容
     *                             2. 在日志中记录对象信息
     *                             3. 在界面上显示对象的摘要信息
     *                             4. 使用System.out.println()打印对象时显示有意义的内容
     * 
     *                             如果不重写toString()，打印对象时会显示类似这样的内容：
     *                             Reservation@1a2b3c4d（类名@对象的哈希码）
     * 
     *                             显示内容包含了预定的关键信息：
     *                             - 预定号：用于识别预定
     *                             - 客人姓名：知道是谁的预定
     *                             - 房间号：知道预定的哪个房间
     *                             - 入住和退房日期：了解时间安排
     *                             - 状态：了解预定的当前状态
     * 
     * @return 预定记录的友好显示格式
     */
    @Override
    public String toString() {
        // 返回包含关键信息的格式化字符串
        // 使用中文标签，方便中文用户理解
        return "预定号: " + reservationId + ", 客人: " + guestName + ", 房间: " + roomNumber +
                ", 入住日期: " + checkInDate + ", 退房日期: " + checkOutDate + ", 状态: " + status;
    }
}